package com.tobeface.wechat.request;

import com.tobeface.modules.helper.JsonHelper;
import com.tobeface.modules.lang.Requires;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Map;

/**
 * @author loudyn
 */
public final class WeChatResponse {

    private final Map<String, Object> firstResult;
    private final Deque<String> actions = new ArrayDeque<String>();
    private final Deque<Object> results = new ArrayDeque<Object>();

    /**
     * @param result
     */
    WeChatResponse(Map<String, Object> result) {
        Requires.notNull(result);
        firstResult = result;
        results.offerLast(result);
    }

    /**
     * @param action
     * @return
     */
    public WeChatResponse on(String action) {
        Requires.hasText(action);
        actions.offerLast(action);
        return this;
    }

    public WeChatResponse back() {

        // call on() but not call get()
        if (results.size() == 1 && !actions.isEmpty()) {
            actions.pollLast();
            return this;
        }

        // neither call on() nor call get()
        if (results.size() <= 1) {
            throw newUnsupportedBackActionException();
        }

        results.pollLast();
        return this;
    }

    private UnsupportedOperationException newUnsupportedBackActionException() {
        return new UnsupportedOperationException("Unable to back ,pls make sure call on() before!");
    }

    /**
     * @return
     */
    public Object get() {

        Object actionResult = results.peekLast();
        while (!actions.isEmpty()) {
            String action = actions.pollFirst();

            if (!(actionResult instanceof Map<?, ?>)) {
                throw newUnsupportedActionException(action);
            }

            Map<String, Object> resultMap = (Map<String, Object>) actionResult;
            if (!resultMap.containsKey(action)) {
                throw newUnsupportedActionException(action);
            }

            actionResult = resultMap.get(action);
            results.offerLast(actionResult);
        }
        return actionResult;
    }

    /**
     * @param type
     * @return
     */
    public <T> T get(Class<T> type) {
        return JsonHelper.transform(get(), type);
    }

    private UnsupportedOperationException newUnsupportedActionException(String action) {
        throw new UnsupportedOperationException("Can't accept the action[" + action + "], pls check the result!");
    }

    /**
     * @return
     */
    public boolean isOK() {
        Integer errcode = getErrorCode();
        return null == errcode || errcode == 0;
    }

    /**
     * @return
     */
    public Integer getErrorCode() {
        return (Integer) firstResult.get("errcode");
    }

    /**
     * @return
     */
    public String getErrorMsg() {
        return (String) firstResult.get("errmsg");
    }

    /**
     * @param content
     * @return
     */
    static WeChatResponse of(byte[] content) {
        Map<String, Object> resultMap = JsonHelper.fromBytes(content, Map.class);
        return new WeChatResponse(resultMap);
    }
}
